package collection

import (
	"iter"

	"gitee.com/gousing/helper/jsoner"
)

// MapSet 泛型化集合, 便捷的SET集合类型数据结构 （无锁, 不适用于并发场景）
type MapSet[T comparable] struct {
	data map[T]struct{}
}

// NewMapSet 创建一个新的MapSet
func NewMapSet[T comparable](size ...int) *MapSet[T] {
	if len(size) > 0 {
		return &MapSet[T]{data: make(map[T]struct{}, size[0])}
	}
	return &MapSet[T]{data: make(map[T]struct{})}
}

// Push 添加元素
//   - 返回值为添加成功的个数
func (s *MapSet[T]) Push(vals ...T) int {
	if len(vals) == 0 {
		return 0
	}
	prevLen := len(s.data)
	for _, v := range vals {
		s.data[v] = struct{}{}
	}
	return len(s.data) - prevLen
}

// Has 快速判断单个元素是否存在
func (s *MapSet[T]) Has(val T) (exists bool) {
	_, exists = s.data[val]
	return
}

// Contains 快速判断多个元素是否全部都存在
func (s *MapSet[T]) Contains(vals ...T) (exists bool) {
	for _, v := range vals {
		if _, ok := s.data[v]; !ok {
			return false
		}
	}
	return true
}

// SomeContains 快速判断是否存在指定多个元素中的某一个
func (s *MapSet[T]) SomeContains(vals ...T) (exists bool) {
	for _, v := range vals {
		if _, ok := s.data[v]; ok {
			return true
		}
	}
	return false
}

// Equal 判断两个集合是否相等
//   - 如果参数集合与当前集合的容量和全部元素是相同的，那么会被然认为是相同的
//   - 不考虑集合元素的顺序
func (s *MapSet[T]) Equal(other *MapSet[T]) bool {
	if len(s.data) != other.Size() {
		return false
	}
	for key := range s.data {
		if !other.Has(key) {
			return false
		}
	}
	return true
}

// Intersect 求当前集合与指定集合的交集
//   - 如果参数集合与当前集合的容量和全部元素是相同的，那么会被然认为是相同的，无需考虑元素的顺序
func (s *MapSet[T]) Intersect(other *MapSet[T]) *MapSet[T] {
	newMap := NewMapSet[T]()
	if len(s.data) < other.Size() {
		for key := range s.data {
			if other.Has(key) {
				newMap.data[key] = struct{}{}
			}
		}
	} else {
		for key := range other.Iter() {
			if s.Has(key) {
				newMap.data[key] = struct{}{}
			}
		}
	}
	return newMap
}

// Difference 求当前集合与指定集合的差集
//   - 并返回一个差集，该差集包括了set集合中部分或全部值，条件为不在指定other集合中的值。
func (s *MapSet[T]) Difference(other *MapSet[T]) *MapSet[T] {
	newMap := NewMapSet[T]()
	for key := range s.data {
		if !other.Has(key) {
			newMap.data[key] = struct{}{}
		}
	}
	return newMap
}

// Union 求当前集合与指定集合的并集
//   - 不考虑元素的顺序，元素顺序是随机的
func (s *MapSet[T]) Union(other *MapSet[T]) *MapSet[T] {
	newMap := s.Clone()
	for key := range other.Iter() {
		newMap.data[key] = struct{}{}
	}
	return newMap
}

// IsSubset 判断当前set集合是否为参数other集合的子集（包含，允许相等）
func (s *MapSet[T]) IsSubset(other *MapSet[T]) bool {
	if len(s.data) > other.Size() {
		return false
	}
	for key := range s.data {
		if !other.Has(key) {
			return false
		}
	}
	return true
}

// IsSuperset 判断参数other集合是否为当前set集合的子集（包含，允许相等）
func (s *MapSet[T]) IsSuperset(other *MapSet[T]) bool {
	return other.IsSubset(s)
}

// IsProperSubset 判断当前set集合是否为参数other集合的真子集（包含但不相等）
func (s *MapSet[T]) IsProperSubset(other *MapSet[T]) bool {
	return s.IsSubset(other) && s.Size() < other.Size()
}

// IsProperSuperset 判断参数other集合是否为当前set集合的真子集（包含但不相等）
func (s *MapSet[T]) IsProperSuperset(other *MapSet[T]) bool {
	return s.IsSuperset(other) && s.Size() > other.Size()
}

// Remove 删除元素
func (s *MapSet[T]) Remove(val T) (exists bool) {
	delete(s.data, val)
	return
}

// Clear 清空集合
func (s *MapSet[T]) Clear() {
	for key := range s.data {
		delete(s.data, key)
	}
}

// IsEmpty 判断集合是否为空
func (s *MapSet[T]) IsEmpty() bool {
	return s.Size() == 0
}

// Size 获取集合元素个数
func (s *MapSet[T]) Size() int {
	return len(s.data)
}

// Iter 集合元素迭代器
//   - 迭代器返回的元素顺序和添加的顺序不一致
//   - for v:=range s.Iter(){}
func (s *MapSet[T]) Iter() iter.Seq[T] {
	return func(yield func(val T) bool) {
		for v := range s.data {
			if !yield(v) {
				return
			}
		}
	}
}

// Values 获取集合元素切片对象(对象是无序的, 顺序和添加的顺序不一致)
func (s *MapSet[T]) Values() []T {
	keys := make([]T, 0, len(s.data))
	for elem := range s.data {
		keys = append(keys, elem)
	}
	return keys
}

// Clone 复制一个集合
func (s *MapSet[T]) Clone() *MapSet[T] {
	newMap := &MapSet[T]{data: make(map[T]struct{}, len(s.data))}
	for key := range s.data {
		newMap.data[key] = struct{}{}
	}
	return newMap
}

// MarshalJSON 序列化集合接口
func (s *MapSet[T]) MarshalJSON() ([]byte, error) {
	items := make([]T, 0, s.Size())
	for elem := range s.data {
		items = append(items, elem)
	}
	return jsoner.Marshal(items)
}

// UnmarshalJSON 反序列化集合接口
func (s *MapSet[T]) UnmarshalJSON(data []byte) error {
	var items []T
	err := jsoner.Unmarshal(data, &items)
	if err != nil {
		return err
	}
	s.Clear()
	if len(items) == 0 {
		return nil
	}
	s.Push(items...)
	return nil
}
